home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / SNNSV32.ZIP / SNNSv3.2 / kernel / sources / dlvq_learn.c < prev    next >
C/C++ Source or Header  |  1994-04-25  |  29KB  |  1,104 lines

  1. /*****************************************************************************
  2.   FILE           : dlvq_learn.c
  3.   SHORTNAME      : 
  4.   SNNS VERSION   : 3.2
  5.  
  6.   PURPOSE        : Functions of DLVQ
  7.   NOTES          :
  8.  
  9.   AUTHOR         : Michael Schmalzl 
  10.   DATE           : 5.2.93
  11.  
  12.   CHANGED BY     : Michael Vogt, Guenter Mamier
  13.   IDENTIFICATION : @(#)dlvq_learn.c    1.9 4/6/94
  14.   SCCS VERSION   : 1.9
  15.   LAST CHANGE    : 4/6/94
  16.  
  17.              Copyright (c) 1990-1994  SNNS Group, IPVR, Univ. Stuttgart, FRG
  18.  
  19. ******************************************************************************/
  20.  
  21. #include <stdio.h>
  22. #include <math.h>
  23. #include <time.h>  
  24. #include <memory.h>
  25. #include <malloc.h>
  26. #include <values.h>
  27.  
  28. #include "kr_typ.h"      /*  Kernel Types and Constants  */
  29. #include "kr_const.h"    /*  Constant Declarators for SNNS-Kernel  */
  30. #include "kr_def.h"      /*  Default Values  */
  31. #include "kernel.h"      /*  kernel function prototypes  */
  32. #include "kr_ui.h"
  33. #include "kr_mac.h"      /*  Kernel Macros   */
  34.  
  35. #include "kr_ui.h"
  36. #include "cc_mac.h"
  37. #include "kr_newpattern.h"
  38. #include "cc_rcc.h"
  39. #include "dlvq_type.h"
  40. #include "dlvq_learn.ph"
  41.  
  42.  
  43. /*****************************************************************************
  44.   FUNCTION : sortHiddenUnitsByClasses
  45.  
  46.   PURPOSE  : Sorts the hidden units by its class.
  47.   NOTES    :
  48.  
  49.   UPDATE   : 5.2.93
  50. ******************************************************************************/
  51. static void sortHiddenUnitsByClasses(int left, int right)
  52. {
  53.     int i,last;
  54.     struct Unit *temp;
  55.  
  56.     if(left >= right ){
  57.     return;
  58.     }
  59.     temp = FirstHiddenUnitPtr[left]; 
  60.     FirstHiddenUnitPtr[left] = FirstHiddenUnitPtr[(left+right)/2]; 
  61.     FirstHiddenUnitPtr[(left+right)/2] = temp;  
  62.     last = left; 
  63.     for(i=left+1;i<=right;i++){
  64.     if(FirstHiddenUnitPtr[i]->bias < FirstHiddenUnitPtr[left]->bias) {
  65.         temp = FirstHiddenUnitPtr[++last]; 
  66.         FirstHiddenUnitPtr[last]=FirstHiddenUnitPtr[i]; 
  67.         FirstHiddenUnitPtr[i]=temp;
  68.     }
  69.     }
  70.     temp = FirstHiddenUnitPtr[left]; 
  71.     FirstHiddenUnitPtr[left]=FirstHiddenUnitPtr[last]; 
  72.     FirstHiddenUnitPtr[last] = temp;
  73.     sortHiddenUnitsByClasses(left,last);
  74.     sortHiddenUnitsByClasses(last+1,right);
  75. }
  76.  
  77.  
  78.  
  79. /*****************************************************************************
  80.   FUNCTION : getNoOfClasses
  81.  
  82.   PURPOSE  : Looks how many different classes exist and checks whether the 
  83.              no. of the first class is zero.
  84.   NOTES    :
  85.  
  86.   UPDATE   : 5.2.93
  87. ******************************************************************************/
  88. krui_err getNoOfClasses(int startPattern, int endPattern)
  89. {
  90.     int p,patternClass=0,maxPatternClass=0,minPatternClass=0;
  91.     int *tmpArray,counter,class;
  92.     int start, end;
  93.     int pat, sub_pat;
  94.     Patterns out_pat;
  95.  
  96.     KernelErrorCode = kr_initSubPatternOrder(startPattern, endPattern);
  97.     if (KernelErrorCode != KRERR_NO_ERROR)
  98.     return KernelErrorCode;
  99.     start = kr_AbsPosOfFirstSubPat(startPattern);
  100.     end   = kr_AbsPosOfFirstSubPat(endPattern);
  101.     end  += kr_NoOfSubPatPairs(endPattern) - 1;
  102.     for(p=start; p<=end;p++){
  103.  
  104.     kr_getSubPatternByNo(&pat, &sub_pat, p);
  105.     out_pat = kr_getSubPatData(pat, sub_pat, OUTPUT, NULL);
  106.  
  107.     patternClass = *out_pat;
  108.     if(patternClass < minPatternClass){
  109.         minPatternClass = patternClass;
  110.     } 
  111.     if(patternClass > maxPatternClass){
  112.         maxPatternClass = patternClass;
  113.     } 
  114.     }
  115.  
  116.     if(minPatternClass != 0){
  117.     return(DLVQ_ERROR2); /* There exists a class smaller than 0 */
  118.     } 
  119.  
  120.     counter = 0;
  121.     p = start;
  122.     tmpArray =  (int *)calloc(maxPatternClass+1,sizeof(int));
  123.  
  124.     while((counter != (maxPatternClass+1)) && (p <= end)){
  125.     kr_getSubPatternByNo(&pat, &sub_pat, p++);
  126.     out_pat = kr_getSubPatData(pat, sub_pat, OUTPUT, NULL);
  127.     class = *out_pat;
  128.     if(tmpArray[class] == 0){
  129.         counter++;
  130.         tmpArray[class] = 1;
  131.     }
  132.     }
  133.     free(tmpArray);
  134.     
  135.     if(counter != (maxPatternClass+1)){
  136.     return(DLVQ_ERROR1); /*  There are empty classes */
  137.     }
  138.     noOfClasses = maxPatternClass+1;
  139.     return(KRERR_NO_ERROR);
  140. }
  141.  
  142.  
  143.  
  144. /*****************************************************************************
  145.   FUNCTION : allocMixupArray
  146.  
  147.   PURPOSE  : Allocate the storage of the "mixupArray".
  148.   NOTES    :
  149.  
  150.   UPDATE   : 5.2.93
  151. ******************************************************************************/
  152. static void allocMixupArray(void)
  153. {
  154.     int i,j;
  155.  
  156.     /* free storage */
  157.     for(i=0;i<oldNoOfClasses;i++) {
  158.     for(j=0;j<oldNoOfClasses;j++) {
  159.         free(mixupArray[i][j].link);
  160.     }
  161.     }
  162.  
  163.     for(i=0;i<oldNoOfClasses;i++) {
  164.     free(mixupArray[i]);
  165.     }
  166.  
  167.     if(mixupArray != NULL) {
  168.     free(mixupArray);
  169.     mixupArray = NULL;
  170.     }
  171.  
  172.     /* alloc storage */
  173.     mixupArray = (struct MIX_UP **)calloc(noOfClasses,sizeof(struct MIX_UP *));
  174.  
  175.     for(i=0;i<noOfClasses;i++) {
  176.     mixupArray[i] = 
  177.         (struct MIX_UP *)calloc(noOfClasses,sizeof(struct MIX_UP));   
  178.     }
  179.  
  180.     for(i=0;i<noOfClasses;i++) {
  181.     for(j=0;j<noOfClasses;j++) {
  182.         mixupArray[i][j].link = 
  183.               (double *)calloc(NoOfInputUnits,sizeof(double));
  184.     }
  185.     }
  186. }
  187.  
  188.  
  189.  
  190. /*****************************************************************************
  191.   FUNCTION : allocLastInsertedUnitArray
  192.  
  193.   PURPOSE  : Allocate the storage of the array "lastInsertedUnitArray".
  194.   NOTES    :
  195.  
  196.   UPDATE   : 5.2.93
  197. ******************************************************************************/
  198. static void allocLastInsertedUnitArray(void)
  199. {
  200.  
  201.     /* free storage */
  202.     if(lastInsertedUnitArray != NULL){
  203.     free(lastInsertedUnitArray);
  204.     lastInsertedUnitArray = NULL;
  205.     }
  206.  
  207.     /* alloc storage */
  208.     lastInsertedUnitArray = (int *)calloc(noOfClasses,sizeof(int));
  209. }
  210.  
  211.  
  212.  
  213. /*****************************************************************************
  214.   FUNCTION : allocInitialUnitArray
  215.  
  216.   PURPOSE  : Allocate the storage of the array "initialUnitArray"
  217.   NOTES    :
  218.  
  219.   UPDATE   : 5.2.93
  220. ******************************************************************************/
  221. void allocInitialUnitArray(void)
  222. {
  223.     int i;
  224.  
  225.     /* free storage */
  226.     for(i=0;i<oldNoOfClasses;i++) {
  227.     free(initialUnitArray[i].link);
  228.     }
  229.  
  230.     if(initialUnitArray != NULL) {
  231.     free(initialUnitArray);
  232.     initialUnitArray = NULL;
  233.     }
  234.  
  235.     /* alloc storage */
  236.     initialUnitArray = 
  237.     (struct MIX_UP *)calloc(noOfClasses,sizeof(struct MIX_UP));
  238.  
  239.     for(i=0;i<noOfClasses;i++) {
  240.     initialUnitArray[i].link = 
  241.         (double *)calloc(NoOfInputUnits,sizeof(double));
  242.     }
  243. }
  244.  
  245.  
  246.  
  247. /*****************************************************************************
  248.   FUNCTION : normPatterns
  249.  
  250.   PURPOSE  : Norm all patterns.
  251.   NOTES    : This function is of no permanent effect since the manipulation 
  252.   of  the input pattern takes place on a copy of the original data.
  253.   Patterns must be normalized before use of DLVQ !!!!!
  254.   Therefore the body of the function is commented out. The original code is 
  255.   left in place to demonstrate the necessary operation. (M. Vogt)
  256.  
  257.   UPDATE   : 5.2.93
  258. ******************************************************************************/
  259. void normPatterns(int startPattern, int endPattern)
  260. {
  261.  
  262. /* see NOTES of funtion header */
  263.  
  264. /*
  265.     double sum,sqrtSum;
  266.     Patterns in_pat,in_patStorage;
  267.     int p,i;
  268.     int start, end;
  269.     int pat, sub;
  270.     int count;
  271.  
  272.     KernelErrorCode = kr_initSubPatternOrder(startPattern,endPattern);
  273.     start = kr_AbsPosOfFirstSubPat(startPattern);
  274.     end   = kr_AbsPosOfFirstSubPat(endPattern);
  275.     end  += kr_NoOfSubPatPairs(endPattern) - 1;
  276.     for(p=start; p<=end;p++){
  277.  
  278.     kr_getSubPatternByNo(&pat,&sub,p);
  279.     in_pat = kr_getSubPatData(pat,sub,INPUT,&count);
  280.     sum = 0.0;  
  281.     in_patStorage = in_pat;  
  282.  
  283.     for(i=0;i<count;i++){   
  284.         sum += (*in_pat) * (*in_pat);
  285.         in_pat++;
  286.     }
  287.     sqrtSum = sqrt(sum);
  288.     in_pat = in_patStorage;
  289.  
  290.     for(i=0;i<count;i++){   
  291.         *in_pat = *in_pat / sqrtSum;
  292.         in_pat++;
  293.     }
  294.     }
  295. */
  296. }
  297.  
  298.  
  299.  
  300. /*****************************************************************************
  301.   FUNCTION : normReferenceVec
  302.  
  303.   PURPOSE  :
  304.   NOTES    :
  305.  
  306.   UPDATE   : 5.2.93
  307. ******************************************************************************/
  308. static void normReferenceVec(struct Unit *hiddenUnitPtr)
  309. {
  310.     double sum,sqrtSum;
  311.     struct Link *linkPtr;
  312.  
  313.     sum = 0.0;
  314.     FOR_ALL_LINKS(hiddenUnitPtr,linkPtr) {
  315.     sum += linkPtr->weight * linkPtr->weight;
  316.     }
  317.  
  318.     sqrtSum = sqrt(sum);
  319.  
  320.     FOR_ALL_LINKS(hiddenUnitPtr,linkPtr){
  321.     linkPtr->weight = linkPtr->weight / sqrtSum;
  322.     }
  323. }
  324.  
  325.  
  326.  
  327. /*****************************************************************************
  328.   FUNCTION : moveVec
  329.  
  330.   PURPOSE  : Train the vectors.
  331.   NOTES    :
  332.  
  333.   UPDATE   : 5.2.93
  334. ******************************************************************************/
  335. static void moveVec(struct Unit *correctReferenceVec, float learnParam1,
  336.                     struct Unit *wrongReferenceVec,   float learnParam2)
  337. {
  338.     struct Link *linkPtr;
  339.  
  340.     FOR_ALL_LINKS(correctReferenceVec,linkPtr){
  341.     linkPtr->weight += learnParam1 * (linkPtr->to->act - linkPtr->weight);
  342.     }
  343.     normReferenceVec(correctReferenceVec);
  344.  
  345.     FOR_ALL_LINKS(wrongReferenceVec,linkPtr){
  346.     linkPtr->weight -= learnParam2 * (linkPtr->to->act - linkPtr->weight);
  347.     }
  348.     normReferenceVec(wrongReferenceVec);
  349. }
  350.  
  351.  
  352.  
  353. /*****************************************************************************
  354.   FUNCTION : 
  355.  
  356.   PURPOSE  :
  357.   NOTES    :
  358.  
  359.   UPDATE   : 5.2.93
  360. ******************************************************************************/
  361. static void writeVectorToMixupArray(int correctClass, int wrongClass, 
  362.                     int patternNo, int sub_pat_no)
  363. {
  364.     Patterns in_pat;
  365.     double *link=NULL;
  366.     int i,count;
  367.  
  368.     /* calculate startaddress for input pattern array  */
  369.     in_pat = kr_getSubPatData(patternNo,sub_pat_no,INPUT,&count);
  370.     link = mixupArray[correctClass][wrongClass].link; 
  371.  
  372.     for(i=0;i<count;i++){
  373.     link[i] = (double)in_pat[i];
  374.     }
  375. }
  376.  
  377.  
  378.  
  379. /*****************************************************************************
  380.   FUNCTION : initInitialUnitArray
  381.  
  382.   PURPOSE  : Init the array "initialUnitArray".
  383.   NOTES    :
  384.  
  385.   UPDATE   : 5.2.93
  386. ******************************************************************************/
  387. void initInitialUnitArray(int startPattern, int endPattern)
  388. {
  389.     int p,i,j;
  390.     Patterns in_pat;
  391.     Patterns out_pat;
  392.     int start, end;
  393.     int pat, sub;
  394.     int count;
  395.  
  396.     KernelErrorCode = kr_initSubPatternOrder(startPattern,endPattern);
  397.     start = kr_AbsPosOfFirstSubPat(startPattern);
  398.     end   = kr_AbsPosOfFirstSubPat(endPattern);
  399.     end  += kr_NoOfSubPatPairs(endPattern) - 1;
  400.     for(p=start; p<=end;p++){
  401.     kr_getSubPatternByNo(&pat,&sub,p);
  402.     in_pat = kr_getSubPatData(pat,sub,INPUT,&count);
  403.     out_pat = kr_getSubPatData(pat,sub,OUTPUT,NULL);
  404.     for(i=0;i<count;i++){
  405.         (initialUnitArray[(int) *out_pat].link)[i] = *in_pat++;
  406.         initialUnitArray[(int) *out_pat].counter++;
  407.     }
  408.     }
  409.     for(i=0;i<noOfClasses;i++){
  410.     for(j=0;j<count;j++){
  411.         (initialUnitArray[i].link)[j] /= initialUnitArray[i].counter;
  412.     }
  413.     }
  414. }
  415.  
  416.  
  417.  
  418. /*****************************************************************************
  419.   FUNCTION : initFirstUnit
  420.  
  421.   PURPOSE  : Init the links of a class unit. Remember: At the beginning of
  422.              the learning there exist no hidden units. The first step of 
  423.              the algorithm inserts for every class a hidden unit. This
  424.              functions inits the links of this first units. The array
  425.              "initialUnitArray" contains for every class the average
  426.              activation over all patterns.
  427.   NOTES    :
  428.  
  429.   UPDATE   : 5.2.93
  430. ******************************************************************************/
  431. static void initFirstUnit(struct Unit *hiddenUnitPtr, int class)
  432. {
  433.     int i;
  434.     struct Link *linkPtr;
  435.     struct Unit *inputUnitPtr;
  436.  
  437.     i = 0;
  438.     FOR_ALL_UNITS(inputUnitPtr){
  439.     if(IS_INPUT_UNIT(inputUnitPtr) && UNIT_IN_USE(inputUnitPtr)){
  440.         inputUnitPtr->act = (initialUnitArray[class].link)[i++];
  441.     }
  442.     }
  443.  
  444.     hiddenUnitPtr->bias = class;
  445.     FOR_ALL_LINKS(hiddenUnitPtr,linkPtr) {
  446.     linkPtr->weight = linkPtr->to->act;
  447.     }
  448.     normReferenceVec(hiddenUnitPtr);
  449. }
  450.  
  451.  
  452.  
  453. /*****************************************************************************
  454.   FUNCTION : deleteAllLinksOfTheOutputUnit
  455.  
  456.   PURPOSE  : 
  457.   NOTES    :
  458.  
  459.   UPDATE   : 5.2.93
  460. ******************************************************************************/
  461. static krui_err deleteAllLinksOfTheOutputUnit(void)
  462. {
  463.     KernelErrorCode = krui_setCurrentUnit(GET_UNIT_NO(*FirstOutputUnitPtr));
  464.     ERROR_CHECK;
  465.  
  466.     krui_deleteAllInputLinks();
  467.     krui_deleteAllOutputLinks();
  468.  
  469.     return(KRERR_NO_ERROR);
  470. }
  471.  
  472.  
  473.  
  474. /*****************************************************************************
  475.   FUNCTION : calculateUnitXYPos
  476.  
  477.   PURPOSE  : Calculates the position of the current input, hidden and output
  478.              layer.
  479.   NOTES    :
  480.  
  481.   UPDATE   : 5.2.93
  482. ******************************************************************************/
  483. static void calculateUnitXYPos(void)
  484. {
  485.     int xPos,yPos,maxXPos=0,maxYPos,minXPos=0,minYPos=0,i,
  486.         xOffset,yOffset,bias,h;
  487.     struct Unit *inputUnitPtr=NULL,*hiddenUnitPtr;
  488.  
  489.     inputUnitPtr = *FirstInputUnitPtr;
  490.     maxXPos = minXPos = GET_UNIT_XPOS(inputUnitPtr);
  491.     maxYPos = minYPos = GET_UNIT_YPOS(inputUnitPtr); 
  492.  
  493.     /* find maxXPos ... of the input layer */
  494.     FOR_ALL_INPUT_UNITS(inputUnitPtr,i) {
  495.     xPos = GET_UNIT_XPOS(inputUnitPtr);
  496.     yPos = GET_UNIT_YPOS(inputUnitPtr);
  497.     if(xPos > maxXPos) {
  498.         maxXPos = xPos;
  499.     }
  500.     if(xPos < minXPos){
  501.         minXPos = xPos;
  502.     }
  503.     if(yPos > maxYPos) {
  504.         maxYPos = yPos;
  505.     }
  506.     if(yPos < minYPos){
  507.         minYPos = yPos;
  508.     }
  509.     }
  510.  
  511.     xOffset = minXPos - 2;
  512.     yOffset = minYPos - 2;
  513.  
  514.     FOR_ALL_INPUT_UNITS(inputUnitPtr,i){
  515.     SET_UNIT_XPOS(inputUnitPtr,GET_UNIT_XPOS(inputUnitPtr) - xOffset);
  516.     SET_UNIT_YPOS(inputUnitPtr,GET_UNIT_YPOS(inputUnitPtr) - yOffset);
  517.     }
  518.  
  519.     bias = (*FirstHiddenUnitPtr)->bias; 
  520.     xPos = (maxXPos - xOffset + 3);
  521.     yPos = 1;
  522.  
  523.     FOR_ALL_HIDDEN_UNITS(hiddenUnitPtr,h){
  524.     if(bias == hiddenUnitPtr->bias){
  525.         yPos++;
  526.     }else{
  527.         xPos++;
  528.         bias = hiddenUnitPtr->bias;
  529.         yPos = 2;
  530.     }
  531.     SET_UNIT_XPOS(hiddenUnitPtr,xPos);
  532.     SET_UNIT_YPOS(hiddenUnitPtr,yPos);
  533.     }   
  534.  
  535.     SET_UNIT_XPOS(*FirstOutputUnitPtr,xPos+3);
  536.     SET_UNIT_YPOS(*FirstOutputUnitPtr,2);
  537. }
  538.  
  539.  
  540.  
  541. /*****************************************************************************
  542.   FUNCTION : insertNewUnits
  543.  
  544.   PURPOSE  : Inserts new hidden units to the net. The weights of the links
  545.              are stored in the "mixupArray". 
  546.   NOTES    :
  547.  
  548.   UPDATE   : 5.2.93
  549. ******************************************************************************/
  550. static krui_err insertNewUnits(void)
  551. {
  552.     int i,j,k,maxCount,maxJ=0,newUnit;
  553.     double sum,sqrtSum,weight;
  554.     struct Unit *newUnitPtr,*inputUnitPtr;
  555.     struct Link *linkPtr;
  556.  
  557.     for(i=0;i<noOfClasses;i++) {
  558.     maxCount = 0;
  559.     for(j=0;j<noOfClasses;j++){
  560.         if(mixupArray[i][j].counter > maxCount) {
  561.         maxCount = mixupArray[i][j].counter;
  562.         maxJ = j;
  563.         }     
  564.     }
  565.     if(maxCount != 0){
  566.  
  567.         /* Generate new unit */
  568.         newUnit = 
  569.         KernelErrorCode = 
  570.             krui_copyUnit(lastInsertedUnitArray[i],INPUTS_AND_OUTPUTS);
  571.         if(KernelErrorCode < 0){
  572.         ERROR_CHECK;
  573.         }
  574.         KernelErrorCode = KRERR_NO_ERROR; 
  575.         newUnitPtr = kr_getUnitPtr(lastInsertedUnitArray[i] = newUnit);
  576.         newUnitPtr->unit_pos.y += 1;     
  577.    
  578.         /*init new unit */
  579.         sum = 0.0;
  580.         k = 0;
  581.         FOR_ALL_UNITS(inputUnitPtr){
  582.         if(IS_INPUT_UNIT(inputUnitPtr) && UNIT_IN_USE(inputUnitPtr)) {
  583.             weight = 
  584.             inputUnitPtr->act = 
  585.                 ((mixupArray[i][maxJ].link)[k++] /
  586.                  mixupArray[i][maxJ].counter);     
  587.             sum += weight * weight;
  588.         }
  589.         }
  590.         sqrtSum = sqrt(sum);
  591.  
  592.         FOR_ALL_LINKS(newUnitPtr,linkPtr) {
  593.         linkPtr->weight = linkPtr->to->act / sqrtSum;
  594.         }
  595.     }
  596.     }
  597.  
  598.     initMixupArray();
  599.  
  600.     return(KRERR_NO_ERROR);
  601.  
  602.  
  603.  
  604. /*****************************************************************************
  605.   FUNCTION : initMixupArray
  606.  
  607.   PURPOSE  : Init the array "mixupArray".
  608.   NOTES    :
  609.  
  610.   UPDATE   : 5.2.93
  611. ******************************************************************************/
  612. static void initMixupArray(void)
  613. {
  614.     int i,j,sizeOfInputVector;
  615.     
  616.     sizeOfInputVector = sizeof(double) * NoOfInputUnits;
  617.  
  618.     for(i=0;i<noOfClasses;i++) {
  619.     for(j=0;j<noOfClasses;j++){
  620.         if(mixupArray[i][j].counter != 0){
  621.         (void)memset(mixupArray[i][j].link,0,sizeOfInputVector);
  622.         mixupArray[i][j].counter = 0;
  623.         }
  624.     }
  625.     }
  626. }
  627.  
  628.  
  629.  
  630. /*****************************************************************************
  631.   FUNCTION :  printMixupArray
  632.  
  633.   PURPOSE  :
  634.   NOTES    :
  635.  
  636.   UPDATE   : 5.2.93
  637. ******************************************************************************/
  638. static void printMixupArray(int cycle)
  639. {
  640.     int i,j;
  641.  
  642.     printf("Cycle %d \n",cycle+1);
  643.     printf("Total number of incorrectly classified items: %d \n",
  644.        wrongClassCounter);
  645.     printf("Array of classified items:\n\n");
  646.  
  647.     for(i=0;i<noOfClasses;i++) {
  648.     for(j=0;j<noOfClasses;j++){
  649.         printf("%d ",mixupArray[i][j].counter);
  650.     }
  651.     printf("\n");
  652.     }
  653.     printf("\n\n");
  654. }
  655.  
  656.  
  657.  
  658. /*****************************************************************************
  659.   FUNCTION : dlvq_trainNet
  660.  
  661.   PURPOSE  :
  662.   NOTES    :
  663.  
  664.   UPDATE   : 5.2.93
  665. ******************************************************************************/
  666. static void dlvq_trainNet(int noOfTrainingCycles, int startPattern,
  667.               int endPattern, float learnParam1, float learnParam2)
  668. {
  669.     struct Unit *correctMaxActivatedUnitPtr=NULL,
  670.     *wrongMaxActivatedUnitPtr=NULL,
  671.     *inputUnitPtr,
  672.     *hiddenUnitPtr;
  673.     double correctMaxAct,wrongMaxAct,act;
  674.     Patterns in_pat;
  675.     Patterns out_pat;
  676.     int i,h,p,j,noOfTrainingCyclesMinus1=noOfTrainingCycles-1;
  677.     struct Link *linkPtr;
  678.     int start, end;
  679.     int pat, sub;
  680.  
  681.     for(j=0;j<noOfTrainingCycles;j++){
  682.  
  683.     KernelErrorCode = kr_initSubPatternOrder(startPattern,endPattern);
  684.     start = kr_AbsPosOfFirstSubPat(startPattern);
  685.     end   = kr_AbsPosOfFirstSubPat(endPattern);
  686.     end  += kr_NoOfSubPatPairs(endPattern) - 1;
  687.     for(p=start; p<=end;p++){
  688.  
  689.         kr_getSubPatternByNo(&pat,&sub,p);
  690.         in_pat = kr_getSubPatData(pat,sub,INPUT,NULL);
  691.         out_pat = kr_getSubPatData(pat,sub,OUTPUT,NULL);
  692.  
  693.         FOR_ALL_INPUT_UNITS(inputUnitPtr,i){
  694.         inputUnitPtr->Out.output = inputUnitPtr->act = *in_pat++;
  695.         }
  696.   
  697.         correctMaxAct = -1.0;
  698.         wrongMaxAct   = -1.0;
  699.         correctMaxActivatedUnitPtr = NULL;
  700.         wrongMaxActivatedUnitPtr = NULL;
  701.  
  702.         FOR_ALL_HIDDEN_UNITS(hiddenUnitPtr,h) {
  703.         act = 0.0;
  704.         FOR_ALL_LINKS(hiddenUnitPtr,linkPtr) {
  705.             act += linkPtr->weight * linkPtr->to->act;
  706.         }
  707.         hiddenUnitPtr->act = act;
  708.  
  709.         if((((int)hiddenUnitPtr->bias) == ((int) *out_pat)) && 
  710.            (act >= correctMaxAct)){
  711.             correctMaxAct = act;
  712.             correctMaxActivatedUnitPtr = hiddenUnitPtr;
  713.         }
  714.         else if((((int)hiddenUnitPtr->bias)!=((int) *out_pat)) && 
  715.             (act >= wrongMaxAct)){
  716.             wrongMaxAct = act;
  717.             wrongMaxActivatedUnitPtr = hiddenUnitPtr;
  718.         }
  719.         }
  720.         if(correctMaxAct <= wrongMaxAct){
  721.         wrongClassCounter++;
  722.         mixupArray[(int) *out_pat]
  723.                   [(int)wrongMaxActivatedUnitPtr->bias].counter++;
  724.         if(j == noOfTrainingCyclesMinus1){
  725.             writeVectorToMixupArray(
  726.                        (int)correctMaxActivatedUnitPtr->bias,
  727.                        (int)wrongMaxActivatedUnitPtr->bias,
  728.                        pat,sub);
  729.         }else{ 
  730.             moveVec(correctMaxActivatedUnitPtr,learnParam1,
  731.                 wrongMaxActivatedUnitPtr,learnParam2);
  732.         }
  733.         }
  734.     } /* end: noOfTrainingCycles */
  735.     printMixupArray(j);  
  736.  
  737.     if(wrongClassCounter == 0){
  738.         continueLearning = 0;
  739.         return;
  740.     }
  741.  
  742.     if(j!=noOfTrainingCyclesMinus1){ 
  743.         initMixupArray();  
  744.         wrongClassCounter = 0;   
  745.     }
  746.     }
  747. }
  748.  
  749.  
  750.  
  751. /*****************************************************************************
  752.   FUNCTION : initLastInsertedUnitArray
  753.  
  754.   PURPOSE  : Init the array lastInsertedUnitArray. This array contains the
  755.              position of the last inserted unit. There is an entry for
  756.              every class.
  757.   NOTES    :
  758.  
  759.   UPDATE   : 5.2.93
  760. ******************************************************************************/
  761. static void initLastInsertedUnitArray(void)
  762. {
  763.     int h,bias;
  764.     struct Unit *hiddenUnitPtr=NULL,*lastUnitPtr=NULL;
  765.  
  766.     bias = (*FirstHiddenUnitPtr)->bias;
  767.     FOR_ALL_HIDDEN_UNITS(hiddenUnitPtr,h){
  768.     if(((int)(hiddenUnitPtr->bias)) == ((int)bias)) {
  769.         lastUnitPtr = hiddenUnitPtr;
  770.     }else{
  771.         lastInsertedUnitArray[(int)lastUnitPtr->bias] =
  772.         GET_UNIT_NO(lastUnitPtr);
  773.         bias = hiddenUnitPtr->bias;
  774.         lastUnitPtr = hiddenUnitPtr;
  775.     }
  776.     }
  777.     lastInsertedUnitArray[(int)lastUnitPtr->bias]=GET_UNIT_NO(lastUnitPtr);
  778.  
  779. }  
  780.  
  781.  
  782.  
  783. /*****************************************************************************
  784.   FUNCTION : dlvq_setPointers
  785.  
  786.   PURPOSE  : Calculates the beginning of the input, hidden, output
  787.              units in the topo_ptr_array.
  788.   NOTES    :
  789.  
  790.   UPDATE   : 5.2.93
  791. ******************************************************************************/
  792. krui_err dlvq_setPointers(void)
  793. {
  794.     FirstInputUnitPtr   = (struct Unit **)(&topo_ptr_array[1]);
  795.     if(*(FirstInputUnitPtr-1)!=NULL) CC_ERROR(KRERR_CC_ERROR1);
  796.     FirstHiddenUnitPtr  = FirstInputUnitPtr  + NoOfInputUnits  + 1;
  797.     if(*(FirstHiddenUnitPtr-1)!=NULL) CC_ERROR(KRERR_CC_ERROR1);
  798.     FirstOutputUnitPtr  = FirstHiddenUnitPtr + NoOfHiddenUnits + 1;
  799.     if(*(FirstOutputUnitPtr-1)!=NULL) CC_ERROR(KRERR_CC_ERROR1);
  800.     return(KRERR_NO_ERROR);
  801. }
  802.  
  803.  
  804.  
  805. /*****************************************************************************
  806.   FUNCTION : generateMissingClassHiddenUnits
  807.  
  808.   PURPOSE  : If all hidden units of a class are removed, this functions 
  809.              generates a new first hidden unit. 
  810.   NOTES    :
  811.  
  812.   UPDATE   : 5.2.93
  813. ******************************************************************************/
  814. void generateMissingClassHiddenUnits(int *generatedNewUnit)
  815. {
  816.     struct Unit *hiddenUnitPtr;
  817.     int i,h;
  818.  
  819.     *generatedNewUnit = 0;
  820.  
  821.     for(i=0;i<noOfClasses;i++){
  822.     lastInsertedUnitArray[i] = 0;
  823.     }
  824.     FOR_ALL_HIDDEN_UNITS(hiddenUnitPtr,h){
  825.     lastInsertedUnitArray[(int)hiddenUnitPtr->bias] = 1;
  826.     }
  827.     for(i=0;i<noOfClasses;i++){
  828.     if(lastInsertedUnitArray[i] == 0) {
  829.         (void)insertFirstUnit(&hiddenUnitPtr);
  830.         initFirstUnit(hiddenUnitPtr,i);
  831.         *generatedNewUnit = 1;
  832.     }else{
  833.         lastInsertedUnitArray[i] = 0;
  834.     } 
  835.     }
  836. }
  837.  
  838.  
  839.  
  840. /*****************************************************************************
  841.   FUNCTION : insertFirstUnit
  842.  
  843.   PURPOSE  : Inserts the first hidden units to the net. For every class one
  844.              unit.
  845.   NOTES    :
  846.  
  847.   UPDATE   : 5.2.93
  848. ******************************************************************************/
  849. static krui_err insertFirstUnit(struct Unit **hiddenUnitPtr)
  850. {
  851.     int hiddenUnit=0;
  852.     struct Unit *inputUnitPtr;
  853.  
  854.     hiddenUnit = KernelErrorCode = krui_createDefaultUnit(); 
  855.     if(KernelErrorCode < 0) {
  856.     ERROR_CHECK;
  857.     }
  858.  
  859.     KernelErrorCode = krui_setUnitTType(hiddenUnit,HIDDEN);  
  860.     ERROR_CHECK;
  861.  
  862.     KernelErrorCode = krui_setUnitActFunc(hiddenUnit,"Act_Identity");
  863.     ERROR_CHECK;
  864.  
  865.     *hiddenUnitPtr = kr_getUnitPtr(hiddenUnit);
  866.     KernelErrorCode = krui_setCurrentUnit(hiddenUnit);
  867.     ERROR_CHECK;
  868.  
  869.     /* generate links between hidden unit and input units */
  870.     FOR_ALL_UNITS(inputUnitPtr) {
  871.     if(IS_INPUT_UNIT(inputUnitPtr) && UNIT_IN_USE(inputUnitPtr)){
  872.         KernelErrorCode = krui_createLink(GET_UNIT_NO(inputUnitPtr),0.0);
  873.         ERROR_CHECK;
  874.     }
  875.     }
  876.  
  877.     /* generate a link between the output unit and the hidden unit */
  878.     KernelErrorCode = krui_setCurrentUnit(GET_UNIT_NO(*FirstOutputUnitPtr));
  879.     ERROR_CHECK;
  880.     KernelErrorCode = krui_createLink(hiddenUnit,1.0); 
  881.     ERROR_CHECK;
  882.     return(KRERR_NO_ERROR);
  883. }
  884.  
  885.  
  886.  
  887. /*****************************************************************************
  888.   FUNCTION : allocArrays
  889.  
  890.   PURPOSE  :
  891.   NOTES    :
  892.  
  893.   UPDATE   : 5.2.93
  894. ******************************************************************************/
  895. void allocArrays(void)
  896. {
  897.     allocMixupArray();
  898.     allocLastInsertedUnitArray();
  899. }
  900.  
  901.  
  902.  
  903. /*****************************************************************************
  904.   FUNCTION : generateTmpTopoPtrArray
  905.  
  906.   PURPOSE  : Generates a topo_ptr_array for local use.
  907.   NOTES    :
  908.  
  909.   UPDATE   : 5.2.93
  910. ******************************************************************************/
  911. static void generateTmpTopoPtrArray(void)
  912. {
  913.     struct Unit *unitPtr;
  914.     TopoPtrArray tmp_array;
  915.  
  916.     if(topo_ptr_array != NULL) {
  917.     free(topo_ptr_array);
  918.     }
  919.  
  920.     tmp_array = 
  921.     topo_ptr_array = 
  922.         (struct Unit **)calloc(NoOfInputUnits+5,sizeof(struct Unit *));
  923.  
  924.     *tmp_array = NULL;
  925.     tmp_array++;
  926.     FOR_ALL_UNITS(unitPtr){
  927.     if(IS_INPUT_UNIT(unitPtr) && UNIT_IN_USE(unitPtr)){
  928.         *tmp_array = unitPtr;
  929.         tmp_array++;
  930.     }
  931.     }
  932.     *tmp_array = NULL;
  933.     tmp_array++;
  934.     *tmp_array = NULL;
  935.     tmp_array++;
  936.     FOR_ALL_UNITS(unitPtr){
  937.     if(IS_OUTPUT_UNIT(unitPtr) && UNIT_IN_USE(unitPtr)){
  938.         *tmp_array = unitPtr;
  939.         tmp_array++;
  940.     }
  941.     }
  942.     *tmp_array = NULL;
  943. }
  944.  
  945.  
  946.  
  947. /*****************************************************************************
  948.   FUNCTION : freeTmpTopoPtrArray
  949.  
  950.   PURPOSE  : Frees the storage of the temporary "topo_ptr_array".
  951.   NOTES    :
  952.  
  953.   UPDATE   : 5.2.93
  954. ******************************************************************************/
  955. static void freeTmpTopoPtrArray(void)
  956. {
  957.     free(topo_ptr_array);
  958.     topo_ptr_array = NULL;
  959. }
  960.  
  961.  
  962.  
  963. /*****************************************************************************
  964.   FUNCTION : LEARN_DLVQ
  965.  
  966.   PURPOSE  : The main learn routine of DLVQ
  967.   NOTES    :
  968.  
  969.   UPDATE   : 5.2.93
  970. ******************************************************************************/
  971. krui_err LEARN_DLVQ(int startPattern, int endPattern, float *ParameterInArray,
  972.             int NoOfInParams, float **ParameterOutArray, 
  973.             int *NoOfOutParams)
  974. {
  975.     static int cycleCounter=0,noOfTrainingCycles=0;
  976.     struct Unit  *unitPtr,*hiddenUnitPtr;
  977.     int i,d1,d2,d3,noOfLinks,generatedNewUnit;
  978.     static float learnParam1=0.03,learnParam2=0.03;
  979.     static float OutParameter[1];
  980.  
  981.     *NoOfOutParams = 1;
  982.     *ParameterOutArray = OutParameter;
  983.  
  984.     if(cc_allButtonIsPressed) {
  985.     continueLearning = 1;
  986.     cycleCounter = 0;
  987.     wrongClassCounter = 0;
  988.     NoOfInputUnits = NoOfHiddenUnits = NoOfOutputUnits = 0;
  989.     FOR_ALL_UNITS(unitPtr) {
  990.         if(IS_INPUT_UNIT(unitPtr) && UNIT_IN_USE(unitPtr)) {
  991.         NoOfInputUnits++;
  992.         }
  993.         if(IS_HIDDEN_UNIT(unitPtr) && UNIT_IN_USE(unitPtr)) {
  994.         NoOfHiddenUnits++;
  995.         }
  996.         if(IS_OUTPUT_UNIT(unitPtr) && UNIT_IN_USE(unitPtr)) {
  997.         NoOfOutputUnits++;
  998.         }
  999.     }
  1000.     if(NoOfOutputUnits != 1){
  1001.         return(DLVQ_ERROR3); /* Wrong no. of output units */
  1002.     }
  1003.  
  1004.     learnParam1 = ParameterInArray[0];
  1005.     learnParam2 = ParameterInArray[1];
  1006.     noOfTrainingCycles = (int)ParameterInArray[2];
  1007.     }
  1008.   
  1009.  
  1010.     if(newPatternsLoaded){
  1011.     newPatternsLoaded = 0;
  1012.     KernelErrorCode = getNoOfClasses(startPattern,endPattern);
  1013.     ERROR_CHECK;
  1014.     normPatterns(startPattern,endPattern);
  1015.     allocInitialUnitArray();
  1016.     initInitialUnitArray(startPattern,endPattern);
  1017.     }
  1018.  
  1019.     if(cc_allButtonIsPressed && (NoOfHiddenUnits == 0)){ /* First time */
  1020.     allocArrays();
  1021.     generateTmpTopoPtrArray();
  1022.     KernelErrorCode = dlvq_setPointers();
  1023.     ERROR_CHECK;
  1024.     KernelErrorCode = deleteAllLinksOfTheOutputUnit();
  1025.     ERROR_CHECK;
  1026.     for(i=0;i<noOfClasses;i++) {
  1027.         KernelErrorCode = insertFirstUnit(&hiddenUnitPtr);
  1028.         ERROR_CHECK;
  1029.         initFirstUnit(hiddenUnitPtr,i);
  1030.     }
  1031.     freeTmpTopoPtrArray();
  1032.     KernelErrorCode = kr_topoSort(TOPOLOGICAL_FF);
  1033.     ERROR_CHECK;     
  1034.     KernelErrorCode = dlvq_setPointers();
  1035.     ERROR_CHECK; 
  1036.  
  1037.     sortHiddenUnitsByClasses(0,noOfClasses-1);
  1038.     calculateUnitXYPos();    
  1039.     initLastInsertedUnitArray();
  1040.  
  1041.     NetModified = FALSE;
  1042.     LearnFuncHasChanged = FALSE;
  1043.     }else if(cc_allButtonIsPressed && (NoOfHiddenUnits != 0)) { 
  1044.  
  1045.     /* Continue learning */
  1046.     if(NetModified || LearnFuncHasChanged){
  1047.         allocArrays();
  1048.         KernelErrorCode = kr_topoSort(TOPOLOGICAL_FF);
  1049.         ERROR_CHECK;    
  1050.         KernelErrorCode = dlvq_setPointers();
  1051.         ERROR_CHECK; 
  1052.         krui_getNetInfo(&d1,&noOfLinks,&d2,&d3);
  1053.         if(noOfLinks != NoOfInputUnits*NoOfHiddenUnits + NoOfHiddenUnits){
  1054.         return(DLVQ_ERROR4); /* the network has a wrong topology */
  1055.         }
  1056.  
  1057.         generateMissingClassHiddenUnits(&generatedNewUnit);
  1058.         if(generatedNewUnit) {
  1059.         KernelErrorCode = kr_topoSort(TOPOLOGICAL_FF);
  1060.         ERROR_CHECK;
  1061.         KernelErrorCode = dlvq_setPointers();
  1062.         ERROR_CHECK; 
  1063.         }
  1064.         NetModified = FALSE;
  1065.         LearnFuncHasChanged = FALSE;
  1066.     }
  1067.       
  1068.     /* even if the net is not modified you have to do the following
  1069.        steps for security. 
  1070.        */  
  1071.     sortHiddenUnitsByClasses(0,NoOfHiddenUnits-1);
  1072.     calculateUnitXYPos();         
  1073.     initLastInsertedUnitArray();
  1074.     }  
  1075.  
  1076.     if(cc_allButtonIsPressed){
  1077.     oldNoOfClasses = noOfClasses;
  1078.     cc_allButtonIsPressed = 0;
  1079.     }
  1080.  
  1081.     if(continueLearning){
  1082.     initMixupArray();
  1083.     dlvq_trainNet(noOfTrainingCycles,startPattern,endPattern,
  1084.               learnParam1,learnParam2);
  1085.     NET_ERROR(OutParameter) = wrongClassCounter;
  1086.     if((cycleCounter<(dlvq_numberOfLearnCycles-1)) &&
  1087.        (wrongClassCounter != 0)){ 
  1088.         /*do not insert new hidden units by the last path through the net*/
  1089.         wrongClassCounter = 0;
  1090.         cycleCounter++; 
  1091.         KernelErrorCode = insertNewUnits();
  1092.         ERROR_CHECK;
  1093.         KernelErrorCode = kr_topoSort(TOPOLOGICAL_FF);
  1094.         ERROR_CHECK;
  1095.         KernelErrorCode = dlvq_setPointers();
  1096.         ERROR_CHECK; 
  1097.     }
  1098.     } 
  1099.     return(KRERR_NO_ERROR);
  1100. }
  1101.  
  1102.  
  1103.